package com.jyniubi.gmall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.jyniubi.gmail.common.bean.ResponseVo;
import com.jyniubi.gmail.common.exception.CartException;
import com.jyniubi.gmail.pms.entity.SkuAttrValueEntity;
import com.jyniubi.gmail.pms.entity.SkuEntity;
import com.jyniubi.gmail.sms.vo.ItemSaleVo;
import com.jyniubi.gmail.wms.entity.WareSkuEntity;
import com.jyniubi.gmall.cart.entity.CartEntity;
import com.jyniubi.gmall.cart.feign.GmallPmsClient;
import com.jyniubi.gmall.cart.feign.GmallSmsClient;
import com.jyniubi.gmall.cart.feign.GmallWmsClient;
import com.jyniubi.gmall.cart.interceptor.LoginInterceptor;
import com.jyniubi.gmall.cart.mapper.CartMapper;
import com.jyniubi.gmall.cart.pojo.UserInfo;
import com.jyniubi.gmall.cart.service.CartService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private GmallPmsClient pmsClient;
    @Autowired
    private GmallSmsClient smsClient;
    @Autowired
    private GmallWmsClient wmsClient;
    @Autowired
    private CartMapper cartMapper;
    @Autowired
    CartAsyncService cartAsyncService;

    private static final String KEY_PREFIX = "cart:info:";

    private static final String PRICE_PREFIX = "cart:price";

    @Override
    public void saveCart(CartEntity cartEntity) {
        // 1. 判断登录状态，userId是登录状态，userKey是未登录状态
        String userId = getUserId();
        // 2. 判断当前用户的购物车是否包含该商品 Map<skuId, CartJson>
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cartEntity.getSkuId().toString();
        // 3. 当前购物车商品数量
        BigDecimal count = cartEntity.getCount();
        if (hashOps.hasKey(skuId)) {
            //当前购物车中已经有该商品，更新商品数量
            String cartJson = hashOps.get(skuId).toString();
            cartEntity = JSON.parseObject(cartJson, CartEntity.class);
            cartEntity.setCount(cartEntity.getCount().add(count));
            this.cartAsyncService.updateCart(userId, skuId, cartEntity);
        } else {
            //当前购物车没有该商品，需要新增商品
            cartEntity.setUserId(userId);
            cartEntity.setCheck(true);
            ResponseVo<SkuEntity> skuEntityResponseVo = this.pmsClient.querySkuById(cartEntity.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity == null) {
                throw new CartException("你要加入购物车的商品不存在！");
            }
            cartEntity.setTitle(skuEntity.getTitle());
            cartEntity.setDefaultImage(skuEntity.getDefaultImage());
            cartEntity.setPrice(skuEntity.getPrice());
            //销售属性
            ResponseVo<List<SkuAttrValueEntity>> skuAttrValueEntityResponse = this.pmsClient.querySaleAttrValuesBySkuId(cartEntity.getSkuId());
            List<SkuAttrValueEntity> skuAttrValueEntities = skuAttrValueEntityResponse.getData();
            if (!CollectionUtils.isEmpty(skuAttrValueEntities)) {
                cartEntity.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));
            }
            //营销信息
            ResponseVo<List<ItemSaleVo>> itemSaleResponse = this.smsClient.querySalesBySkuId(cartEntity.getSkuId());
            List<ItemSaleVo> itemSaleVos = itemSaleResponse.getData();
            if (!CollectionUtils.isEmpty(itemSaleVos)) {
                cartEntity.setSales(JSON.toJSONString(itemSaleVos));
            }
            //库存信息
            ResponseVo<List<WareSkuEntity>> wareSkuResponse = this.wmsClient.querySkuById(cartEntity.getSkuId());
            List<WareSkuEntity> wareSkuEntities = wareSkuResponse.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                cartEntity.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock() - wareSkuEntity.getStockLocked() > 0));
            }
            this.cartAsyncService.insertCart(userId, cartEntity);
            // 缓存实时价格
            this.redisTemplate.opsForValue().set(PRICE_PREFIX + skuId, cartEntity.getPrice().toString());
        }
        hashOps.put(skuId, JSON.toJSONString(cartEntity));
    }

    @Override
    public CartEntity queryCartById(Long skuId) {
        /*// 获取登录状态
        String userId = this.getUserId();

        // 获取用户的内层的map
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (hashOps.hasKey(skuId.toString())){
            String cartJson = hashOps.get(skuId.toString()).toString();
            return JSON.parseObject(cartJson, CartEntity.class);
        }
        throw new CartException("您的购物车没有该商品记录！");*/
        // 获取用户id
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();
        String userId = null;
        if (userInfo.getUserId() != null) {
            userId = userInfo.getUserId().toString();
        }
        //userInfo.getUserId不管为空和不为空都检查下未登录状态下的购物车
        //todo：在登录状态下查询下未登录状态的购物车是否为空
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (hashOps.hasKey(skuId.toString())){
            String cartJson = hashOps.get(skuId.toString()).toString();
            return JSON.parseObject(cartJson, CartEntity.class);
        }else {
            //todo:这里有一个特殊情况，就是用户在未登录状态下添加商品到购物车，
            // 跳转到addCart.html这个页面，在这个页面直接登录，因为重定向地址是addCart.html,
            // 而此时还没进行购物车合并，就会出现没有商品记录的情况
            // 用户不管有没有登录都会有userKey,如果用户直接在addCart.html页面登录的话
            // 登录状态购物车为空，但未登录状态购物车可能包含此商品，所以用userKey查询购物车
            BoundHashOperations<String, Object, Object> unLoginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userKey);
            if (unLoginHashOps.hasKey(skuId.toString())) {
                String unLoginCartJson = unLoginHashOps.get(skuId.toString()).toString();
                return JSON.parseObject(unLoginCartJson, CartEntity.class);
            }
        }
        throw new CartException("您的购物车没有该商品记录！");
    }

    @Override
    public List<CartEntity> queryCart() {
        // 通过拦截器获取用户信息
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        // 获取未登录用户Id userKey
        String userKey = userInfo.getUserKey();
        // 用户不管有没有登录都会有userKey 所以直接用userKey查询购物车
        BoundHashOperations<String, Object, Object> unLoginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userKey);
        List<Object> unLoginCartJsons = unLoginHashOps.values();
        // 未登录状态购物车不为空
        List<CartEntity> unLoginCarts = null;
        if (!CollectionUtils.isEmpty(unLoginCartJsons)) {
            unLoginCarts = unLoginCartJsons.stream().map(unLoginCartJson -> {
                CartEntity cart = JSON.parseObject(unLoginCartJson.toString(), CartEntity.class);
                String currentPrice = this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId());
                //if (!StringUtils.isEmpty(currentPrice)){
                cart.setCurrentPrice(new BigDecimal(currentPrice));
                //}
                return cart;
            }).collect(Collectors.toList());
        }
        Long userId = userInfo.getUserId();
        // 如果userId为空，说明是未登录状态
        if (userId == null) {
            return unLoginCarts;
        }
        // 合并已登录和未登录的购物车
        BoundHashOperations<String, Object, Object> loginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!CollectionUtils.isEmpty(unLoginCarts)) {
            unLoginCarts.forEach(cart -> {
                String skuId = cart.getSkuId().toString();
                BigDecimal count = cart.getCount();
                // 登录购物车中包含此商品 合并购物车
                if (loginHashOps.hasKey(skuId)) {
                    String loginCartsJson = loginHashOps.get(skuId).toString();
                    cart = JSON.parseObject(loginCartsJson, CartEntity.class);
                    cart.setCount(cart.getCount().add(count));
                    this.cartAsyncService.updateCart(userId.toString(), skuId, cart);
                } else {
                    //登录购物车不包含改商品，购物车新增商品
                    cart.setUserId(userId.toString());
                    cart.setId(null);
                    this.cartAsyncService.insertCart(userId.toString(), cart);
                }
                loginHashOps.put(skuId, JSON.toJSONString(cart));
            });
            // 清空未登录的购物车商品
            this.cartAsyncService.deleteCartByUserId(userKey);
            this.redisTemplate.delete(KEY_PREFIX + userKey);
        }
        // 返回合并后的购物车
        List<Object> cartsJson = loginHashOps.values();
        if (!CollectionUtils.isEmpty(cartsJson)) {
            List<CartEntity> cartEntities = cartsJson.stream().map(cartJson -> {
                CartEntity cart = JSON.parseObject(cartJson.toString(), CartEntity.class);
                String currentPrice = this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId());
                //if (!StringUtils.isEmpty(currentPrice)){
                cart.setCurrentPrice(new BigDecimal(currentPrice));
                //}
                return cart;
            }).collect(Collectors.toList());
            return cartEntities;
        }
        return null;
    }


    @Override
    public void updateNum(CartEntity cartEntity) {
        String userId = this.getUserId();
        BigDecimal count = cartEntity.getCount();
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cartEntity.getSkuId().toString();
        if (!hashOps.hasKey(skuId)) {
            throw new CartException("你没有对应的购物车记录！");
        }
        String cartJson = hashOps.get(skuId).toString();
        cartEntity = JSON.parseObject(cartJson, CartEntity.class);
        cartEntity.setCount(count);
        hashOps.put(skuId, JSON.toJSONString(cartEntity));
        this.cartAsyncService.updateCart(userId, skuId, cartEntity);

    }

    @Override
    public void deleteCart(Long skuId) {
        String userId = this.getUserId();
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!hashOps.hasKey(skuId.toString())) {
            throw new CartException("你没有对应的购物车记录！");
        }
        hashOps.delete(skuId.toString());
        this.cartAsyncService.deleteCartByUserIdAndSkuId(userId, skuId);
    }

    @Override
    public List<CartEntity> queryCheckedCarts(Long userId) {
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        List<Object> cartJsons = hashOps.values();
        if (CollectionUtils.isEmpty(cartJsons)) {
            return null;
        }
        return cartJsons.stream().map(cartJson -> JSON.parseObject(cartJson.toString(), CartEntity.class)).filter(CartEntity::getCheck).collect(Collectors.toList());
    }

    private String getUserId() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userId = userInfo.getUserKey();
        if (userInfo.getUserId() != null) {
            userId = userInfo.getUserId().toString();
        }
        return userId;
    }

    //--------------------测试--------------------

    @Async
    @Override
    public void execute1() {
        try {
            System.out.println("execute1方法开始执行。");
            TimeUnit.SECONDS.sleep(4);
            //int i = 1/0;
            System.out.println("execute1方法结束执行执行---------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //return AsyncResult.forValue("execute1方法返回结果");
    }

    @Async
    @Override
    public void execute2() {
        try {
            System.out.println("execute2方法开始执行。");
            TimeUnit.SECONDS.sleep(5);
            int i = 1 / 0;
            System.out.println("execute2方法结束执行执行---------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //return AsyncResult.forValue("execute2方法返回结果");
    }

}
